package app

import (
	"fmt"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
	"sync"

	"gitee.com/tomatomeatman/golang-repository/bricks/model/emity"
	"gitee.com/tomatomeatman/golang-repository/bricks/utils/function/data/aesutil"
	Log "github.com/cihub/seelog"
	"gopkg.in/ini.v1"
)

var (
	appCfg             *ini.File //配置文件变量
	glbAppiCloudApp    = 0       //是否要加入分布式系统(0:待初始化;1:是;2:否)
	glbAppiCloudSystem = 0       // 判断程序是否启用桥接
	once               sync.Once
)

type AppUtil struct{}

// 判断程序是否要加入分布式系统
func (au AppUtil) IsCloudApp() bool {
	if glbAppiCloudApp != 0 {
		return glbAppiCloudApp == 1
	}

	if au.HasSection("CloudCenter") {
		glbAppiCloudApp = 1
		return true
	}

	glbAppiCloudApp = 2
	return false
}

// 判断程序是否非分布式系统
func (au AppUtil) IsNotCloudApp() bool {
	return !au.IsCloudApp()
}

// 判断程序是否启用桥接
func (au AppUtil) IsCloudSystem() bool {
	if glbAppiCloudSystem != 0 {
		return glbAppiCloudSystem == 1
	}

	if au.HasSection("CloudSystem") {
		glbAppiCloudSystem = 1
		return true
	}

	glbAppiCloudSystem = 2
	return false
}

// 判断程序是否禁用桥接
func (au AppUtil) IsNotCloudSystem() bool {
	return !au.IsCloudSystem()
}

// 判断配置组是否存在
func (au AppUtil) HasSection(sectionName string) bool {
	au.iniCfg()

	section, _ := appCfg.GetSection(sectionName) // return appCfg.HasSection(sectionName)//这种方式不安全

	if section == nil {
		return false
	}

	if len(section.Keys()) == 0 {
		return false
	}

	return true
}

// 读取配置值
func (au AppUtil) ReadConfigKey(section, key string, def interface{}) interface{} {
	au.iniCfg()

	title := appCfg.Section(section)
	value, _ := title.GetKey(key)
	if value == nil {
		return def
	}

	if def == nil {
		def = ""
	}

	isEncrypt := false
	temp := fmt.Sprintf("%v", value)
	if strings.HasPrefix(temp, "${") && strings.HasSuffix(temp, "}") {
		isEncrypt = true
		temp = aesutil.Decrypt(temp[2:len(temp)-1], "bricks")
	}

	switch def.(type) {
	case string: // 将interface转为string字符串类型
		if isEncrypt {
			return temp
		}
		return value.String()
	case int:
		if isEncrypt {
			result, err := strconv.Atoi(temp)
			if err != nil {
				return def
			}
			return result
		}

		result, err := value.Int()
		if err != nil {
			return def
		}

		return result
	case int64:
		if isEncrypt {
			result, err := strconv.ParseInt(temp, 10, 64)
			if err != nil {
				return def
			}
			return result
		}

		result, err := value.Int64()
		if err != nil {
			return def
		}

		return result
	case float64:
		if isEncrypt {
			result, err := strconv.ParseFloat(temp, 64)
			if err != nil {
				return def
			}
			return result
		}

		result, err := value.Float64()
		if err != nil {
			return def
		}

		return result
	case bool:
		if isEncrypt {
			result, err := strconv.ParseBool(temp) //接受 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False 等字符串；
			if err != nil {
				return def
			}
			return result
		}

		result, err := value.Bool()
		if err != nil {
			return def
		}

		return result
	default:
		return value.String()
	}
}

// 初始化配置文件变量
func (au AppUtil) iniCfg() {
	once.Do(func() {
		root := ""
		exePath, err := os.Executable()
		if err != nil {
			root = "."
		}

		root, _ = filepath.EvalSymlinks(filepath.Dir(exePath))

		configFilePath := strings.Replace(root+"/config/app.ini", "\\", "/", -1)

		_, err = os.Stat(configFilePath) //os.Stat获取文件信息
		if err != nil {
			if !os.IsExist(err) {
				Log.Error("配置文件不存在", err)
				return
			}
		}

		appCfg, err = ini.Load(configFilePath)
		if err != nil {
			Log.Error("配置文件读取错误", err)
			return
		}
	})
}

/**
 * 通过结构体获取
 * @param entity 结构体样式
 * @param names 辅助'项名称',若不传递则按结构体名称做'项名称'
 * @return 返回新建结构体实体
 */
func (au AppUtil) ToEntity(entity interface{}, names ...string) *emity.MsgEmity {
	if entity == nil {
		entity = map[string]interface{}{}
	}

	au.iniCfg()

	rt := reflect.TypeOf(entity)
	rve := reflect.New(rt).Elem()

	if len(names) < 1 {
		sName := rt.Name()
		if strings.Contains(sName, "map[string]") || strings.HasPrefix(sName, "[]") {
			return emity.MsgEmity{}.Err(1002, "不明确的配置项,无法进行解析")
		}

		names = append(names, sName)
	}

	for _, sName := range names {
		section := appCfg.Section(sName)
		for k := 0; k < rt.NumField(); k++ {
			value, _ := section.GetKey(rt.Field(k).Name)
			if value == nil {
				continue
			}

			field := rve.FieldByName(rt.Field(k).Name)
			if !field.IsValid() {
				continue
			}

			{
				temp := value.String()
				if strings.Contains(temp, "${") {
					continue //配置中含有变量符,不获取(待改进)
				}
			}

			switch field.Type().String() {
			case "string":
				field.Set(reflect.ValueOf(value.String()))
			case "int":
				temp, err := value.Int()
				if err != nil {
					continue
				}

				field.Set(reflect.ValueOf(temp))
			case "int64":
				temp, err := value.Int64()
				if err != nil {
					continue
				}

				field.Set(reflect.ValueOf(temp))
			case "bool":
				temp, err := value.Bool()
				if err != nil {
					continue
				}

				field.Set(reflect.ValueOf(temp))
			case "float64":
				temp, err := value.Float64()
				if err != nil {
					continue
				}

				field.Set(reflect.ValueOf(temp))
			default:
				field.Set(reflect.ValueOf(value.String()))
			}
		}
	}

	result := rve.Interface()

	return emity.MsgEmity{}.Success(result, "转换结束")
}

/**
 * 释放配置文件
 */
func FreeappCfg() {
	appCfg = nil
}
